﻿using BaseDll;
using CommonTools;
using FinalTest_Algonrithm;
using FinalTest_Algonrithm.Clibra;
using ModuleCapture;
using Newtonsoft.Json;
using StationDemo.utils;
using Sunny.UI;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using UserData;

namespace StationDemo
{
    public class Param_标定站
    {
        public ParamSet 轴到位后延时 = new ParamSet()
        {
            _enuValType = ParamSetUnit.intUnit,
            _strParamUnit = "轴到位后延时",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 1000,
            _ParamRight = UserRight.Operator,
            _ParamClass = "综合",
            b_IsStartCheck = true,
        };
        public ParamSet 出图延时 = new ParamSet()
        {
            _enuValType = ParamSetUnit.intUnit,
            _strParamUnit = "出图延时",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 1000,
            _ParamRight = UserRight.Operator,
            _ParamClass = "综合",
            b_IsStartCheck = true,
        };

        public ParamSet 平面图卡角点行数 = new ParamSet()
        {
            _enuValType = ParamSetUnit.intUnit,
            _strParamUnit = "平面图卡角点行数",
            _strParamValMax = 1000,
            _strParamValMin = 1,
            _strParamVal = 1,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定对心",
            b_IsStartCheck = true,
        };
        public ParamSet 平面图卡角点列数 = new ParamSet()
        {
            _enuValType = ParamSetUnit.intUnit,
            _strParamUnit = "平面图卡角点列数",
            _strParamValMax = 1000,
            _strParamValMin = 1,
            _strParamVal = 1,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定对心",
            b_IsStartCheck = true,
        };
        public ParamSet 对心X偏差上限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.intUnit,
            _strParamUnit = "对心X偏差最大值",
            _strParamValMax = 1000,
            _strParamValMin = 1,
            _strParamVal = 1,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定对心",
            b_IsStartCheck = true,
        };
        public ParamSet 对心Y偏差上限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.intUnit,
            _strParamUnit = "对心Y偏差最大值",
            _strParamValMax = 1000,
            _strParamValMin = 1,
            _strParamVal = 1,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定对心",
            b_IsStartCheck = true,
        };
        public ParamSet 对心X反向 = new ParamSet()
        {
            _enuValType = ParamSetUnit.boolUnit,
            _strParamUnit = "对心X反向",
            _strParamValMax = true,
            _strParamValMin = false,
            _strParamVal = false,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定对心",
            b_IsStartCheck = true,
        };
        public ParamSet 对心Y反向 = new ParamSet()
        {
            _enuValType = ParamSetUnit.boolUnit,
            _strParamUnit = "对心Y反向",
            _strParamValMax = true,
            _strParamValMin = false,
            _strParamVal = false,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定对心",
            b_IsStartCheck = true,
        };
        public ParamSet 对心比例 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "对心比例",
            _strParamValMax = 1000000.0,
            _strParamValMin = 0.0,
            _strParamVal = 0.0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定对心",
            b_IsStartCheck = true,
        };

        public ParamSet 采图数量 = new ParamSet()
        {
            _enuValType = ParamSetUnit.intUnit,
            _strParamUnit = "采图数量",
            _strParamValMax = 1000,
            _strParamValMin = 1,
            _strParamVal = 1,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定",
            b_IsStartCheck = true,
        };
        public ParamSet 标定模型 = new ParamSet()
        {
            _enuValType = ParamSetUnit.intUnit,
            _strParamUnit = "标定模型，0-小图卡小孔3K模型，1-小图卡小孔6K模型,2-鱼眼模型",
            _strParamValMax = 6,
            _strParamValMin = 0,
            _strParamVal = 0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定",
            b_IsStartCheck = true,
        };
        public ParamSet 重投影上限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "重投影上限",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定规格",
            b_IsStartCheck = true,
        };
        public ParamSet Cx上限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "Cx上限",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定规格",
            b_IsStartCheck = true,
        };
        public ParamSet Cx下限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "Cx下限",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定规格",
            b_IsStartCheck = true,
        };
        public ParamSet Cy上限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "Cy上限",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定规格",
            b_IsStartCheck = true,
        };
        public ParamSet Cy下限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "Cy下限",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定规格",
            b_IsStartCheck = true,
        };
        public ParamSet FxFy上限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "重投影上限",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定规格",
            b_IsStartCheck = true,
        };
        public ParamSet FxFy下限 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "FxFy下限",
            _strParamValMax = 600000,
            _strParamValMin = 0,
            _strParamVal = 0,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定规格",
            b_IsStartCheck = true,
        };
        public ParamSet 小图卡X方向偏移距离 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "小图卡偏移距离",
            _strParamValMax = 5.0,
            _strParamValMin = 0.1,
            _strParamVal = 0.5,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定",
            b_IsStartCheck = true,
        };
        public ParamSet 小图卡Y方向偏移距离 = new ParamSet()
        {
            _enuValType = ParamSetUnit.doubleUnit,
            _strParamUnit = "小图卡偏移距离",
            _strParamValMax = 5.0,
            _strParamValMin = 0.1,
            _strParamVal = 0.5,
            _ParamRight = UserRight.Operator,
            _ParamClass = "标定",
            b_IsStartCheck = true,
        };

    }
    public class Point_标定站
    {
    }

    public class Config_标定站
    {
        [Category("外部标定软件"), DisplayName("外部标定软件路径"), Description("当需要使用外挂软件进行标定时，请在此处维护外挂软件的全路径")]
        public string ExternClibrationSoftwarePath { set; get; } = "";

        [Category("外部标定软件"), DisplayName("外部标定软件标题名称"), Description("当需要使用外挂软件进行标定时，请在此处维护外挂软件的标题名称")]
        public string ExternClibrationSoftwareTitleText { set; get; } = "";
    }
    public class Station_标定站 : CommonTools.StationbaseEx<Param_标定站, Point_标定站, Config_标定站>
    {


        #region 变量

        private bool isCreateSoftWare = false;

        Station_Load station_load = null;
        Station_Table station_table = null;

        StationInfor clibraStation = new StationInfor(SOCKET.SOCKETB);

        public Func<ProductData, bool, bool> FlashProductData = null;

        public Func<IntPtr, bool> FuncSetExternSoft { get; set; } = null;


        public Station_标定站(CommonTools.Stationbase station, Param_标定站 param, Point_标定站 point, Config_标定站 config) : base(station, param, point, config)
        {

        }

        public enum StationStep
        {
            [Description("0.初始化步骤")]
            Step_Init = 100,
            [Description("1.等待转盘到位")]
            Step_等待转盘到位,
            [Description("2.检测当前工位产品")]
            Step_CheckProduct,
            [Description("3.开始测试")]
            Step_标定测试,
            [Description("4.结束流程")]
            Step_End,
        }
        #endregion


        #region 主流程
        
        protected override void StationWork(int step)
        {
            try
            {
                switch (step)
                {
                    case (int)StationStep.Step_Init:
                        DelCurrentStep();
                        PushMultStep((int)StepInitRun());
                        break;
                    case (int)StationStep.Step_等待转盘到位:
                        DelCurrentStep();
                        PushMultStep((int)Step_等待转盘到位());
                        break;
                    case (int)StationStep.Step_CheckProduct:
                        DelCurrentStep();
                        PushMultStep((int)Step_CheckProduct());
                        break;
                    case (int)StationStep.Step_标定测试:
                        DelCurrentStep();
                        PushMultStep((int)Step_标定测试());
                        break;
                    case (int)StationStep.Step_End:
                        DelCurrentStep();
                        PushMultStep((int)StepEnd());
                        Thread.Sleep(10);
                        break;
                }
            }
            catch (Exception ex)
            {
                LogHelper.OnTest_ShowLog(Name, $"{Name} 发生错误:{ex.StackTrace},{ex.Message}", LogType.Err);
                StationMgr.GetInstance().Stop();
            }
        }

        protected override bool InitStation()
        {

            if(!isCreateSoftWare)
                isCreateSoftWare = StartExternSoftware();

            ClearAllStep();
            PushMultStep((int)StationStep.Step_Init);
            station_load = (Station_Load)StationMgr.GetInstance().GetStation(Station.上料站.ToString());
            station_table = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            clibraStation = new StationInfor(SOCKET.SOCKETB);
            return true;
        }

        #endregion


        #region 方法

        private StationStep StepInitRun(bool bmanual = false)
        {
            LogHelper.OnTest_ShowLog(Name, $"start wait table", LogType.Warn);
            return StationStep.Step_等待转盘到位;
        }

        private StationStep Step_等待转盘到位(bool bmanual = false)
        {
            if (station_table.TableStatus == TABLESTATUS.stop || station_table.TableStatus == TABLESTATUS.ready_load)//等待转盘到位，测试开始信号
            {
                LogHelper.OnTest_ShowLog(Name, $"转盘旋转到位，开始流程", LogType.Warn);
                return StationStep.Step_CheckProduct;
            }
            return StationStep.Step_等待转盘到位;
        }

        private StationStep Step_CheckProduct(bool bmanual = false)
        {
            string productJson = station_table.Function_GetProduct(Station.标定站);
            this.clibraStation = JsonConvert.DeserializeObject<StationInfor>(productJson);

            if (this.clibraStation.SOCKETSTATUS == SOCKETSTATUS.HaveProductCanTest)
            {
                LogHelper.OnTest_ShowLog(Name, $"有产品，开始标定");
                return StationStep.Step_标定测试;
            }
            else
            {
                LogHelper.OnTest_ShowLog(Name, $"无产品，跳过");
                return StationStep.Step_End;
            }
        }

        private StationStep Step_标定测试(bool bmanual = false)
        {
            Station_Table table = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            (string capBoxSN, Station_治具 station_治具) = table.Function_Get硬件信息();

            int clibraModel = station_Param.标定模型._strParamVal;
            bool isOK = false;
            string msg = "";
            FlashProductData?.Invoke(null, true);

            switch (clibraModel)
            {
                case 0:
                    {
                        isOK = Function_针孔模型3K标定测试(out msg);
                    }
                    break;
                case 1:
                    {
                        isOK = Function_针孔模型6K标定测试(out msg);
                    }
                    break;
                case 2:
                    {
                        isOK = Function_鱼眼模型标定测试(out msg);
                    }
                    break;
            }

            Station_Table table1 = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            (string capBoxSN1, Station_治具 station_治具站) = table.Function_Get硬件信息();
            station_治具站.Function_运动到指定点位(0, bmanual);

            if (!isOK)
                LogHelper.OnTest_ShowLog(Name, $"标定ng：\n{msg}", LogType.Err);

            if (!Param_System.Instance.外接标定程序._strParamVal)
                station_load.Function_CapImg(capBoxSN, true, out msg);
            else
                LoadSeverMgr.Instance.Functio_停止取图();

            LogHelper.OnTest_ShowLog(Name, $"采集停止", LogType.Warn);
            LogHelper.OnTest_ShowLog(Name, $"标定结果：{isOK}");

            this.clibraStation.SOCKETSTATUS = SOCKETSTATUS.HaveProductTestEnd;

            return StationStep.Step_End;
        }

        private StationStep StepEnd(bool bmanual = false)
        {
            // 通知转盘
            StationStateHelper.OnTest_ShowStep(Name, "开始通知转盘", LogType.Warn);
            LogHelper.OnTest_ShowLog(Name, "开始通知转盘");
            station_table.Function_NotifyTestEnd(Station.标定站, JsonConvert.SerializeObject(this.clibraStation));
            Thread.Sleep(100);
            StationStateHelper.OnTest_ShowStep(Name, "等待转盘到位", LogType.Warn);
            return StationStep.Step_等待转盘到位;
        }

        public override void StopDeal()
        {
        }

        private bool StartExternSoftware()
        {
            Process mfcProcess = new Process();
            mfcProcess.StartInfo.FileName = station_Config.ExternClibrationSoftwarePath; // 替换为实际的MFC程序文件名
            mfcProcess.Start();

            // 等待MFC程序启动
            mfcProcess.WaitForInputIdle();

            // 获取MFC程序的主窗口句柄
            IntPtr mfcWindowHandle = SystemDLL.FindWindow(null, station_Config.ExternClibrationSoftwareTitleText); // 替换为实际的MFC程序窗口标题

            if (mfcWindowHandle != IntPtr.Zero)
            {
                // 隐藏标题栏
                int style = SystemDLL.GetWindowLong(mfcWindowHandle, SystemDLL.GWL_STYLE);
                style &= ~SystemDLL.WS_CAPTION;
                SystemDLL.SetWindowLong(mfcWindowHandle, SystemDLL.GWL_STYLE, style);

                return (bool)(FuncSetExternSoft?.Invoke(mfcWindowHandle));
            }
            else
            {
                return false;
            }
        }


        private bool Function_计算图卡中心(out double cx, out double cy, out Bitmap destBmp, bool bmanual = false)
        {

            cx = 0; cy = 0; destBmp = null;
            Station_Table table = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            (string capBoxSN, Station_治具 station_治具) = table.Function_Get硬件信息();
            Station_Load station_load = (Station_Load)StationMgr.GetInstance().GetStation(Station.上料站.ToString());

            int imageW = station_load.station_Param.出图图像宽._strParamVal;
            int imageH = station_load.station_Param.出图图像高._strParamVal;

            int rowNum = station_Param.平面图卡角点行数._strParamVal;
            int colNum = station_Param.平面图卡角点列数._strParamVal;

            Bitmap bmp = station_load.Function_GetBMP(capBoxSN);
            VisionBaseLib.VisionBaseMgr.GetInstance().OnTest_ShowImage(bmanual ? "" : "标定AUTO", bmp, bmp);
            byte[] srcImageByteArray = ModuleCaptureMgr.ConvertBitmapToByteArray(bmp);
            byte[] destImageByteArray = new byte[srcImageByteArray.Length];
            int dllAPI = 0;
            unsafe
            {
                fixed (byte* srcImageByteArrayPtr = srcImageByteArray)
                {
                    fixed (byte* destImageByteArrayPtr = destImageByteArray)
                    {
                        try
                        {
                            dllAPI = HuayaLibCalib.hy_get_chart_center(0, srcImageByteArrayPtr, ref cx, ref cy, destImageByteArrayPtr, rowNum, colNum);
                            destBmp = ModuleCaptureMgr.ConvertBinaryToBitmap(destImageByteArray, imageW, imageH);
                            VisionBaseLib.VisionBaseMgr.GetInstance().OnTest_ShowImage(bmanual ? "" : "标定AUTOF", destBmp, destBmp);
                            return dllAPI == 1;
                        }
                        catch (Exception)
                        {
                            return false;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 图卡对中心
        /// </summary>
        /// <returns></returns>
        public bool Function_ChartCenter(out string msg, out Bitmap destBmp, bool bmanual = false)
        {
            destBmp = null;
            msg = "";

            string configPath = HuayaLibCalib.ConfigPath(ParamSetMgr.GetInstance().CurrentProductFile);
            int v = HuayaLibCalib.hy_load_configs(configPath, 1);
            if (v != 1)
            {
                UIMessageBox.ShowError($"hy_load_configs error api:{v}");
                return false;
            }

            Station_Table table = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            (string capBoxSN, Station_治具 station_治具) = table.Function_Get硬件信息();

            double cx = 0.0, cy = 0.0;
            bool dllAPI = Function_计算图卡中心(out cx, out cy, out destBmp, bmanual);

            if (dllAPI)
            {
                return Function_MoveChar(station_治具, cx, cy, bmanual);
            }

            destBmp = null;
            return false;
        }

        public bool Function_计算比例(out string msg)
        {
            msg = "";
            string configPath = HuayaLibCalib.ConfigPath(ParamSetMgr.GetInstance().CurrentProductFile);
            int v = HuayaLibCalib.hy_load_configs(configPath, 1);
            if (v != 1)
            {
                UIMessageBox.ShowError($"hy_load_configs error api:{v}");
                return false;
            }
            Station_Table table = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            (string capBoxSN, Station_治具 station_治具) = table.Function_Get硬件信息();

            bool f1 = Function_计算图卡中心(out double cx, out double cy, out Bitmap destBmp);

            var movePos = 5.0;
            station_治具.Function_运动相对偏差(movePos, 0, true);
            Thread.Sleep(100);
            bool f2 = Function_计算图卡中心(out double cx1, out double cy1, out Bitmap destBmp1);

            msg = $"手动界面日志, 移动：{movePos},像素中心偏差{cx1 - cx}，比例：{(cx1 - cx) / movePos}";
            return false;
        }

        public bool Function_MoveChar(Station_治具 station_治具, double cx, double cy, bool bmanual = false)
        {
            if (Math.Abs(cx) > station_Param.对心X偏差上限._strParamVal || Math.Abs(cy) > station_Param.对心Y偏差上限._strParamVal)
            {
                LogHelper.OnTest_ShowLog(Name, "对心超出上限");
                return false;
            }

            if (station_Param.对心X反向._strParamVal)
                cx = -cx;
            if (station_Param.对心Y反向._strParamVal)
                cy = -cy;

            double bl = station_Param.对心比例._strParamVal;
            cx /= bl;
            cy /= bl;

            station_治具.Function_运动相对偏差(cx, cy, bmanual);
            return true;
        }

        private void Function_CommonProcess(string imagePath, int imageW, int imageH, int byteNum)
        {
            double Coverage = 0;
            byte[] coverageImageByteArray = new byte[byteNum];
            unsafe
            {
                fixed (byte* coverageImageByteArrayPtr = coverageImageByteArray)
                {
                    try
                    {
                        StationStateHelper.OnTest_ShowStep(Name, "计算覆盖率", LogType.Warn);
                        HuayaLibCalib.hy_get_coverage(0, ref Coverage, coverageImageByteArrayPtr);
                        Bitmap coverageImageBmp = ModuleCaptureMgr.ConvertBinaryToBitmap(coverageImageByteArray, imageW, imageH);
                        string coverageImagePath = $"{imagePath}imagecoverage_{1}.bmp";
                        coverageImageBmp.Save(coverageImagePath, System.Drawing.Imaging.ImageFormat.Bmp);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.OnTest_ShowLog(Name, $"存图失败,{ex.Message}");
                    }
                }
            }

            this.clibraStation.productData.coverage.Value = Coverage;

            byte[] undistortImageByteBuffer = new byte[byteNum];
            Bitmap imageUndistor = null;
            unsafe
            {
                fixed (byte* undistortImageByteBufferPtr = undistortImageByteBuffer)
                {
                    try
                    {
                        StationStateHelper.OnTest_ShowStep(Name, "获取反畸变图", LogType.Warn);
                        HuayaLibCalib.hy_get_undistort_image(0, 0, undistortImageByteBufferPtr);
                        imageUndistor = ModuleCaptureMgr.ConvertBinaryToBitmap(undistortImageByteBuffer, station_load.station_Param.出图图像宽._strParamVal, station_load.station_Param.出图图像高._strParamVal);
                        Bitmap showImageUndistor = (Bitmap)imageUndistor.Clone();
                        VisionBaseLib.VisionBaseMgr.GetInstance().OnTest_ShowImage("标定AUTOF", showImageUndistor, showImageUndistor);
                        string cornersImagePath = $"{imagePath}imageUndistor_{1}.bmp";
                        imageUndistor.Save(cornersImagePath, System.Drawing.Imaging.ImageFormat.Bmp);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.OnTest_ShowLog(Name, $"存图失败,{ex.Message}");
                    }
                }
            }
        }

        public bool Function_针孔模型3K标定测试(out string msg, bool bmanual = false)
        {
            msg = "";

            string configPath = HuayaLibCalib.ConfigPath(ParamSetMgr.GetInstance().CurrentProductFile);
            int v = HuayaLibCalib.hy_load_configs(configPath, 1);
            if (v != 1)
            {
                UIMessageBox.ShowError($"hy_load_configs error api:{v}");
                return false;
            }


            PathHelper.n_CalibModel = 1;
            string path = PathHelper.ProductCsvPath;
            string sn = clibraStation.productData.sn.Value == "" ? "None" + DateTime.Now.ToString("HHssmm") : clibraStation.productData.sn.Value;
            string imagePath = $"{Directory.GetParent(path).FullName}\\{sn}\\";
            if (!Directory.Exists(imagePath))
                Directory.CreateDirectory(imagePath);


            Station_Load station_load = (Station_Load)StationMgr.GetInstance().GetStation(Station.上料站.ToString());
            Station_Table table = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            (string capBoxSN, Station_治具 station_治具) = table.Function_Get硬件信息();

            int imageW = station_load.station_Param.出图图像宽._strParamVal;
            int imageH = station_load.station_Param.出图图像高._strParamVal;
            double pyX = station_Param.小图卡X方向偏移距离._strParamVal;
            double pyY = station_Param.小图卡Y方向偏移距离._strParamVal;


            // 先到第一张图卡位置
            station_治具.Function_运动到指定点位(1, bmanual);
            Thread.Sleep(station_Param.轴到位后延时._strParamVal);


            // 对心
            StationStateHelper.OnTest_ShowStep(Name, "开始对心", LogType.Warn);
            bool c = Function_ChartCenter(out msg, out Bitmap centerBmp);
            if (!c)
                return false;

            string centerImagePath = $"{imagePath}centerImage.bmp";
            centerBmp?.Save(centerImagePath, System.Drawing.Imaging.ImageFormat.Bmp);

            StationStateHelper.OnTest_ShowStep(Name, "开始拍图", LogType.Warn);
            station_治具.Function_运动相对偏差(-pyX, -pyY, bmanual);
            station_治具.Function_GetPos(out double posTx, out double posTz);
            int i = 0;
            int byteNum = 0;
            for (int col = 0; col < 3; col++)
                for (int row = 0; row < 3; row++)
                {
                    double toPosTz = posTz + row * pyX;
                    double toPosTx = posTx + col * pyY;

                    station_治具.Function_MoveTxTzPos(toPosTx, toPosTz, bmanual);

                    StationStateHelper.OnTest_ShowStep(Name, $"图{i + 1}", LogType.Warn);
                    Bitmap bitmap = station_load.Function_GetBMP(capBoxSN);
                    Bitmap showBmp = (Bitmap)bitmap.Clone();
                    VisionBaseLib.VisionBaseMgr.GetInstance().OnTest_ShowImage(bmanual ? "BD" : "标定AUTO", showBmp, showBmp);

                    byte[] srcImageByteArray = ModuleCaptureMgr.ConvertBitmapToByteArray(bitmap);
                    byte[] connerImageByteArray = new byte[srcImageByteArray.Length];
                    byteNum = srcImageByteArray.Length;
                    unsafe
                    {
                        fixed (byte* srcImageBufferPtr = srcImageByteArray)
                        {
                            fixed (byte* cornersImageByteBufferPtr = connerImageByteArray)
                            {
                                try
                                {
                                    string srcImagePath = $"{imagePath}imageSrc_{i + 1}.bmp";
                                    bitmap.Save(srcImagePath, System.Drawing.Imaging.ImageFormat.Bmp);
                                    int v2 = HuayaLibCalib.hy_get_corners(0, 0, srcImageBufferPtr, (row == 0 && col == 0), cornersImageByteBufferPtr);
                                    Bitmap destBmp = ModuleCaptureMgr.ConvertBinaryToBitmap(connerImageByteArray, imageW, imageH);
                                    string cornersImagePath = $"{imagePath}Corners\\imageCorners_{i++ + 1}.bmp";
                                    if (!Directory.Exists(Directory.GetParent(cornersImagePath).FullName))
                                        Directory.CreateDirectory(Directory.GetParent(cornersImagePath).FullName);
                                    destBmp.Save(cornersImagePath, System.Drawing.Imaging.ImageFormat.Bmp);
                                }
                                catch (Exception ex)
                                {
                                    msg = ex.Message;
                                    return false;
                                }
                            }
                        }
                    }

                    Thread.Sleep(50);
                }


            double ReproErr = 0;
            double Cx = 0;
            double Cy = 0;
            double Fx = 0;
            double Fy = 0;
            double[] K = new double[3];
            double[] P = new double[2];
            LogHelper.OnTest_ShowLog(Name, $"[{station_Param.标定模型._strParamVal}]-小孔模型3K", LogType.Warn);
            StationStateHelper.OnTest_ShowStep(Name, "开始标定", LogType.Warn);
            int nResult = HuayaLibCalib.hy_start_calib_cv_pinhole_3k(0, ref ReproErr, ref Cx, ref Cy, ref Fx, ref Fy, K, P);

            Function_CommonProcess(imagePath, imageW, imageH, byteNum);

            string ResultString = string.Format($"Result: {nResult}\n");
            ResultString = string.Format($"{ResultString} ReproErr: {ReproErr}\n");
            ResultString = string.Format($"{ResultString} Cx: {Cx}\n");
            ResultString = string.Format($"{ResultString} Cy: {Cy}\n");
            ResultString = string.Format($"{ResultString} Fx: {Fx}\n");
            ResultString = string.Format($"{ResultString} Fy: {Fy}\n");
            ResultString = string.Format($"{ResultString} K1: {K[0]}\n");
            ResultString = string.Format($"{ResultString} K2: {K[1]}\n");
            ResultString = string.Format($"{ResultString} K3: {K[2]}\n");
            ResultString = string.Format($"{ResultString} P1: {P[0]}\n");
            ResultString = string.Format($"{ResultString} P2: {P[1]}\n");

            clibraStation.productData.ST.Value = DateTime.Now.ToString();
            clibraStation.productData.fx.Value = Fx;
            clibraStation.productData.fy.Value = Fy;
            clibraStation.productData.Cx.Value = Cx;
            clibraStation.productData.Cy.Value = Cy;
            clibraStation.productData.K1.Value = K[0];
            clibraStation.productData.K2.Value = K[1];
            clibraStation.productData.K3.Value = K[2];
            clibraStation.productData.P1.Value = P[0];
            clibraStation.productData.P2.Value = P[1];
            clibraStation.productData.reproErr.Value = ReproErr;

            clibraStation.productData.socketName.Value = clibraStation.socket.ToString();
            clibraStation.productData.reproErr.Max = ((double)station_Param.重投影上限._strParamVal).ToString();
            clibraStation.productData.reproErr.Min = (0.0).ToString();

            clibraStation.productData.fx.Max = ((double)station_Param.FxFy上限._strParamVal).ToString();
            clibraStation.productData.fx.Min = ((double)station_Param.FxFy下限._strParamVal).ToString();
            clibraStation.productData.fy.Max = ((double)station_Param.FxFy上限._strParamVal).ToString();
            clibraStation.productData.fy.Min = ((double)station_Param.FxFy下限._strParamVal).ToString();

            clibraStation.productData.Cx.Max = ((double)station_Param.Cx上限._strParamVal).ToString();
            clibraStation.productData.Cx.Min = ((double)station_Param.Cx下限._strParamVal).ToString();
            clibraStation.productData.Cy.Max = ((double)station_Param.Cy上限._strParamVal).ToString();
            clibraStation.productData.Cy.Min = ((double)station_Param.Cy下限._strParamVal).ToString();
            bool? r = FlashProductData?.Invoke(clibraStation.productData, false);
            clibraStation.productData.result.Value = r;

            try
            {
                CSVHelper.Instance.SaveToCSVPath(path, clibraStation.productData, true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                try
                {
                    CSVHelper.Instance.SaveToCSVPath(path, clibraStation.productData, true);
                }
                catch (Exception ex1)
                {
                    LogHelper.OnTest_ShowLog(Name, $"{ex1.Message}");
                }
            }

            station_治具.Function_运动到指定点位(0, bmanual);
            msg = ResultString;
            StationStateHelper.OnTest_ShowStep(Name, "标定结束", LogType.Warn);
            return true;
        }

        public bool Function_针孔模型6K标定测试(out string msg, bool bmanual = false)
        {
            msg = "";

            string configPath = HuayaLibCalib.ConfigPath(ParamSetMgr.GetInstance().CurrentProductFile);
            int v = HuayaLibCalib.hy_load_configs(configPath, 1);
            if (v != 1)
            {
                UIMessageBox.ShowError($"hy_load_configs error api:{v}");
                return false;
            }


            PathHelper.n_CalibModel = 1;
            string path = PathHelper.ProductCsvPath;
            string sn = clibraStation.productData.sn.Value == "" ? "None" + DateTime.Now.ToString("HHssmm") : clibraStation.productData.sn.Value;
            string imagePath = $"{Directory.GetParent(path).FullName}\\{sn}\\";
            if (!Directory.Exists(imagePath))
                Directory.CreateDirectory(imagePath);


            Station_Load station_load = (Station_Load)StationMgr.GetInstance().GetStation(Station.上料站.ToString());
            Station_Table table = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            (string capBoxSN, Station_治具 station_治具) = table.Function_Get硬件信息();

            int imageW = station_load.station_Param.出图图像宽._strParamVal;
            int imageH = station_load.station_Param.出图图像高._strParamVal;
            double pyX = station_Param.小图卡X方向偏移距离._strParamVal;
            double pyY = station_Param.小图卡Y方向偏移距离._strParamVal;


            // 先到第一张图卡位置
            station_治具.Function_运动到指定点位(1, bmanual);
            Thread.Sleep(station_Param.轴到位后延时._strParamVal);


            // 对心
            StationStateHelper.OnTest_ShowStep(Name, "开始对心", LogType.Warn);
            bool c = Function_ChartCenter(out msg, out Bitmap centerBmp);
            if (!c)
                return false;

            string centerImagePath = $"{imagePath}centerImage.bmp";
            centerBmp?.Save(centerImagePath);

            StationStateHelper.OnTest_ShowStep(Name, "开始拍图", LogType.Warn);
            station_治具.Function_运动相对偏差(-pyX, -pyY, bmanual);
            station_治具.Function_GetPos(out double posTx, out double posTz);
            int i = 0;
            int byteNum = 0;
            for (int col = 0; col < 3; col++)
                for (int row = 0; row < 3; row++)
                {
                    double toPosTz = posTz + row * pyX;
                    double toPosTx = posTx + col * pyY;

                    station_治具.Function_MoveTxTzPos(toPosTx, toPosTz, bmanual);

                    StationStateHelper.OnTest_ShowStep(Name, $"图{i + 1}", LogType.Warn);
                    Bitmap bitmap = station_load.Function_GetBMP(capBoxSN);
                    Bitmap showBmp = (Bitmap)bitmap.Clone();
                    VisionBaseLib.VisionBaseMgr.GetInstance().OnTest_ShowImage(bmanual ? "BD" : "标定AUTO", showBmp, showBmp);

                    byte[] srcImageByteArray = ModuleCaptureMgr.ConvertBitmapToByteArray(bitmap);
                    byte[] connerImageByteArray = new byte[srcImageByteArray.Length];
                    byteNum = srcImageByteArray.Length;
                    unsafe
                    {
                        fixed (byte* srcImageBufferPtr = srcImageByteArray)
                        {
                            fixed (byte* cornersImageByteBufferPtr = connerImageByteArray)
                            {
                                try
                                {
                                    string srcImagePath = $"{imagePath}imageSrc_{i + 1}.bmp";
                                    bitmap.Save(srcImagePath, System.Drawing.Imaging.ImageFormat.Bmp);
                                    int v2 = HuayaLibCalib.hy_get_corners(0, 0, srcImageBufferPtr, (row == 0 && col == 0), cornersImageByteBufferPtr);
                                    Bitmap destBmp = ModuleCaptureMgr.ConvertBinaryToBitmap(connerImageByteArray, imageW, imageH);
                                    string cornersImagePath = $"{imagePath}Corners\\imageCorners_{i++ + 1}.bmp";
                                    if (!Directory.Exists(Directory.GetParent(cornersImagePath).FullName))
                                        Directory.CreateDirectory(Directory.GetParent(cornersImagePath).FullName);
                                    destBmp.Save(cornersImagePath, System.Drawing.Imaging.ImageFormat.Bmp);
                                }
                                catch (Exception ex)
                                {
                                    msg = ex.Message;
                                    return false;
                                }
                            }
                        }
                    }

                    Thread.Sleep(50);
                }


            double ReproErr = 0;
            double Cx = 0;
            double Cy = 0;
            double Fx = 0;
            double Fy = 0;
            double[] K = new double[6];
            double[] P = new double[2];
            LogHelper.OnTest_ShowLog(Name, $"[{station_Param.标定模型._strParamVal}]-小孔模型6K", LogType.Warn);
            StationStateHelper.OnTest_ShowStep(Name, "开始标定", LogType.Warn);
            int nResult = HuayaLibCalib.hy_start_calib_cv_pinhole_6k(0, ref ReproErr, ref Cx, ref Cy, ref Fx, ref Fy, K, P);

            Function_CommonProcess(imagePath, imageW, imageH, byteNum);

            string ResultString = string.Format($"Result: {nResult}\n");
            ResultString = string.Format($"{ResultString} ReproErr: {ReproErr}\n");
            ResultString = string.Format($"{ResultString} Cx: {Cx}\n");
            ResultString = string.Format($"{ResultString} Cy: {Cy}\n");
            ResultString = string.Format($"{ResultString} Fx: {Fx}\n");
            ResultString = string.Format($"{ResultString} Fy: {Fy}\n");
            ResultString = string.Format($"{ResultString} K1: {K[0]}\n");
            ResultString = string.Format($"{ResultString} K2: {K[1]}\n");
            ResultString = string.Format($"{ResultString} K3: {K[2]}\n");
            ResultString = string.Format($"{ResultString} K4: {K[3]}\n");
            ResultString = string.Format($"{ResultString} K5: {K[4]}\n");
            ResultString = string.Format($"{ResultString} K6: {K[5]}\n");
            ResultString = string.Format($"{ResultString} P1: {P[0]}\n");
            ResultString = string.Format($"{ResultString} P2: {P[1]}\n");

            clibraStation.productData.ST.Value = DateTime.Now.ToString();
            clibraStation.productData.fx.Value = Fx;
            clibraStation.productData.fy.Value = Fy;
            clibraStation.productData.Cx.Value = Cx;
            clibraStation.productData.Cy.Value = Cy;
            clibraStation.productData.K1.Value = K[0];
            clibraStation.productData.K2.Value = K[1];
            clibraStation.productData.K3.Value = K[2];
            clibraStation.productData.K4.Value = K[3];
            clibraStation.productData.K5.Value = K[4];
            clibraStation.productData.K6.Value = K[5];
            clibraStation.productData.P1.Value = P[0];
            clibraStation.productData.P2.Value = P[1];
            clibraStation.productData.reproErr.Value = ReproErr;

            clibraStation.productData.socketName.Value = clibraStation.socket.ToString();
            clibraStation.productData.reproErr.Max = ((double)station_Param.重投影上限._strParamVal).ToString();
            clibraStation.productData.reproErr.Min = (0.0).ToString();

            clibraStation.productData.fx.Max = ((double)station_Param.FxFy上限._strParamVal).ToString();
            clibraStation.productData.fx.Min = ((double)station_Param.FxFy下限._strParamVal).ToString();
            clibraStation.productData.fy.Max = ((double)station_Param.FxFy上限._strParamVal).ToString();
            clibraStation.productData.fy.Min = ((double)station_Param.FxFy下限._strParamVal).ToString();

            clibraStation.productData.Cx.Max = ((double)station_Param.Cx上限._strParamVal).ToString();
            clibraStation.productData.Cx.Min = ((double)station_Param.Cx下限._strParamVal).ToString();
            clibraStation.productData.Cy.Max = ((double)station_Param.Cy上限._strParamVal).ToString();
            clibraStation.productData.Cy.Min = ((double)station_Param.Cy下限._strParamVal).ToString();
            bool? r = FlashProductData?.Invoke(clibraStation.productData, false);
            clibraStation.productData.result.Value = r;

            try
            {
                CSVHelper.Instance.SaveToCSVPath(path, clibraStation.productData, true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                try
                {
                    CSVHelper.Instance.SaveToCSVPath(path, clibraStation.productData, true);
                }
                catch (Exception ex1)
                {
                    LogHelper.OnTest_ShowLog(Name, $"{ex1.Message}");
                }
            }

            msg = ResultString;
            StationStateHelper.OnTest_ShowStep(Name, "标定结束", LogType.Warn);
            return true;
        }

        public bool Function_鱼眼模型标定测试(out string msg, bool bmanual = false)
        {
            msg = "";


            string configPath = HuayaLibCalib.ConfigPath(ParamSetMgr.GetInstance().CurrentProductFile);
            int v = HuayaLibCalib.hy_load_configs(configPath, 1);
            if (v != 1)
                return false;

            // invoke clibra api

            PathHelper.n_CalibModel = 2;
            string path = PathHelper.ProductCsvPath;
            string sn = clibraStation.productData.sn.Value == "" ? "None" + DateTime.Now.ToString("HHssmm") : clibraStation.productData.sn.Value;
            string imagePath = $"{Directory.GetParent(path).FullName}\\{sn}\\";
            if (!Directory.Exists(imagePath))
                Directory.CreateDirectory(imagePath);

            Station_Table table = (Station_Table)StationMgr.GetInstance().GetStation(Station.转盘站.ToString());
            (string capBoxSN, Station_治具 station_治具站) = table.Function_Get硬件信息();
            int imageW = station_load.station_Param.出图图像宽._strParamVal;
            int imageH = station_load.station_Param.出图图像高._strParamVal;

            Bitmap bmp = null;
            byte[] srcImageByteBuffer = null;
            for (int i = 0; i < station_Param.采图数量._strParamVal; i++)
            {
                station_治具站.Function_运动到指定点位(i + 1, bmanual);
                Thread.Sleep(station_Param.轴到位后延时._strParamVal);

                if (Param_System.Instance.外接标定程序._strParamVal)
                {
                    bool v1 = LoadSeverMgr.Instance.Function_取图(LoadSeverMgr.Instance.server1, i);
                    if(v1)
                    {
                        LogHelper.OnTest_ShowLog(Name, $"[{i}]-Function_取图 OK", LogType.Warn);
                    }
                    else
                    {
                        LogHelper.OnTest_ShowLog(Name, $"[{i}]-Function_取图 NG", LogType.Err);
                        return false;
                    }
                }
                else
                {
                    for (int j = 0; j < 3; j++)
                    {
                        bmp = station_load.Function_GetBMP(capBoxSN);
                        if (bmp != null)
                        {
                            Bitmap showBmp1 = (Bitmap)bmp.Clone();
                            VisionBaseLib.VisionBaseMgr.GetInstance().OnTest_ShowImage("标定AUTO", showBmp1, showBmp1);
                            Thread.Sleep(station_Param.出图延时._strParamVal);
                        }
                    }

                    if (bmp == null)
                    {
                        LogHelper.OnTest_ShowLog(Name, $"bmp == null");
                        return false;
                    }
                    Bitmap showBmp = (Bitmap)bmp.Clone();
                    //Bitmap saveBmp = (Bitmap)bmp.Clone();
                    VisionBaseLib.VisionBaseMgr.GetInstance().OnTest_ShowImage("标定AUTO", showBmp, showBmp);

                    srcImageByteBuffer = ModuleCaptureMgr.ConvertBitmapToByteArray(bmp);
                    byte[] cornersImageByteBuffer = new byte[srcImageByteBuffer.Length];
                    Bitmap imageConner = null;
                    unsafe
                    {
                        fixed (byte* srcImageBufferPtr = srcImageByteBuffer)
                        {
                            fixed (byte* cornersImageByteBufferPtr = cornersImageByteBuffer)
                            {
                                try
                                {
                                    string srcImagePath = $"{imagePath}imageSrc_{i + 1}.bmp";
                                    bmp.Save(srcImagePath, System.Drawing.Imaging.ImageFormat.Bmp);
                                    int v2 = HuayaLibCalib.hy_get_corners(0, 0, srcImageBufferPtr, i == 0, cornersImageByteBufferPtr);
                                    imageConner = ModuleCaptureMgr.ConvertBinaryToBitmap(cornersImageByteBuffer, imageW, imageH);
                                    Bitmap showImageConner = (Bitmap)imageConner.Clone();
                                    VisionBaseLib.VisionBaseMgr.GetInstance().OnTest_ShowImage("标定AUTO", showImageConner, showImageConner);
                                    string cornersImagePath = $"{imagePath}imageCornersImagePath_{i + 1}.bmp";
                                    imageConner.Save(cornersImagePath, System.Drawing.Imaging.ImageFormat.Bmp);
                                }
                                catch (Exception ex)
                                {
                                    LogHelper.OnTest_ShowLog(Name, $"存图失败,{ex.Message}");
                                }
                            }
                        }
                    }
                }
            }

            if (Param_System.Instance.外接标定程序._strParamVal)
            {
                double[] value = new double[64];
                clibraStation.productData.result.Value= LoadSeverMgr.Instance.Function_标定计算(LoadSeverMgr.Instance.server1, out value);
                return clibraStation.productData.result.Value;
            }

            double ReproErr = 0;
            double Cx = 0;
            double Cy = 0;
            double Fx = 0;
            double Fy = 0;


            LogHelper.OnTest_ShowLog(Name, $"[{station_Param.标定模型._strParamVal}]-鱼眼模型", LogType.Warn);
            double[] K = new double[4];
            int nResult = HuayaLibCalib.hy_start_calib_cv_fisheye(0, ref ReproErr, ref Cx, ref Cy, ref Fx, ref Fy, K);

            Function_CommonProcess(imagePath, imageW, imageH, srcImageByteBuffer.Length);

            string ResultString = string.Format($"Result: {nResult}\n");
            ResultString = string.Format($"{ResultString} ReproErr: {ReproErr}\n");
            ResultString = string.Format($"{ResultString} Cx: {Cx}\n");
            ResultString = string.Format($"{ResultString} Cy: {Cy}\n");
            ResultString = string.Format($"{ResultString} Fx: {Fx}\n");
            ResultString = string.Format($"{ResultString} Fy: {Fy}\n");
            ResultString = string.Format($"{ResultString} K1: {K[0]}\n");
            ResultString = string.Format($"{ResultString} K2: {K[1]}\n");
            ResultString = string.Format($"{ResultString} K3: {K[2]}\n");
            ResultString = string.Format($"{ResultString} K4: {K[3]}\n");
            LogHelper.OnTest_ShowLog(Name, ResultString, LogType.Warn);

            clibraStation.productData.ST.Value = DateTime.Now.ToString();
            clibraStation.productData.fx.Value = Fx;
            clibraStation.productData.fy.Value = Fy;
            clibraStation.productData.Cx.Value = Cx;
            clibraStation.productData.Cy.Value = Cy;
            clibraStation.productData.K1.Value = K[0];
            clibraStation.productData.K2.Value = K[1];
            clibraStation.productData.K3.Value = K[2];
            clibraStation.productData.K4.Value = K[3];
            clibraStation.productData.reproErr.Value = ReproErr;

            clibraStation.productData.socketName.Value = clibraStation.socket.ToString();
            clibraStation.productData.reproErr.Max = ((double)station_Param.重投影上限._strParamVal).ToString();
            clibraStation.productData.reproErr.Min = (0.0).ToString();

            clibraStation.productData.fx.Max = ((double)station_Param.FxFy上限._strParamVal).ToString();
            clibraStation.productData.fx.Min = ((double)station_Param.FxFy下限._strParamVal).ToString();
            clibraStation.productData.fy.Max = ((double)station_Param.FxFy上限._strParamVal).ToString();
            clibraStation.productData.fy.Min = ((double)station_Param.FxFy下限._strParamVal).ToString();

            clibraStation.productData.Cx.Max = ((double)station_Param.Cx上限._strParamVal).ToString();
            clibraStation.productData.Cx.Min = ((double)station_Param.Cx下限._strParamVal).ToString();
            clibraStation.productData.Cy.Max = ((double)station_Param.Cy上限._strParamVal).ToString();
            clibraStation.productData.Cy.Min = ((double)station_Param.Cy下限._strParamVal).ToString();
            bool? r = FlashProductData?.Invoke(clibraStation.productData, false);
            clibraStation.productData.result.Value = r;

            try
            {
                CSVHelper.Instance.SaveToCSVPath(path, clibraStation.productData, true);
            }
            catch (Exception ex)
            {
                LogHelper.OnTest_ShowLog(Name, $"{ex.Message}");
            }

            StationStateHelper.OnTest_ShowStep(Name, "标定结束", LogType.Warn);
            return (bool)r;
        }

        #endregion
    }
}
